package qj.ui;

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import qj.util.ThreadUtil4;

public class ClipboardObserver {
	private static final ClipboardObserver INSTANCE = new ClipboardObserver();

	private static int SLEEP_TIME = 100;

	private List clipboardChangeListenerList = new ArrayList();
	private List clipboardTextChangeListenerList = new ArrayList();
	private boolean goon = true;
	private Thread thread;
	
	private ClipboardObserver() {
		System.out.println("Sniffing clipboard");
		
		thread = new Thread() {
			public void run() {
				
				Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
				try {
					oldClipboardString = (String) clipboard.getContents(null).getTransferData(DataFlavor.stringFlavor);
				} catch (UnsupportedFlavorException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				while (goon) {
					ThreadUtil4.sleep(SLEEP_TIME);
					checkClipboard();
				}				
			}

		};
		thread.start();
	}
	
	/**
	 * This stop sniffing process until other call to getInstance
	 *
	 */
	public void halt() {
		goon = false;
	}

	public void addListener(ClipboardChangeListener listener) {
		clipboardChangeListenerList.add(listener);
	}

	public void addListener(ClipboardTextChangeListener listener) {
		clipboardTextChangeListenerList.add(listener);
	}
	
	private String oldClipboardString = null;
	/**
	 * 
	 */
	private void checkClipboard() {
		try {
			Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
			String newString = (String) clipboard.getContents(null).getTransferData(DataFlavor.stringFlavor);
			
			if ((newString == null ^ oldClipboardString == null)
					|| (newString != null && ! newString.equals(oldClipboardString))) {
				for (int i = 0; i < clipboardChangeListenerList.size(); i++) {
					ClipboardChangeListener lis = (ClipboardChangeListener) clipboardChangeListenerList.get(i);
					lis.clipboardUpdated(clipboard);
				}
				
				for (int i = 0; i < clipboardTextChangeListenerList.size(); i++) {
					ClipboardTextChangeListener lis = (ClipboardTextChangeListener) clipboardTextChangeListenerList.get(i);
					clipboard.setContents(new StringSelection(lis.clipboardUpdated((String) clipboard.getContents(null).getTransferData(DataFlavor.stringFlavor))), null);
				}
			}
			
			oldClipboardString = (String) clipboard.getContents(null).getTransferData(DataFlavor.stringFlavor);
		} catch (IllegalStateException e) {
			System.out.println(e);
		} catch (UnsupportedFlavorException e) {
			System.out.println(e);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) throws UnsupportedFlavorException, IOException {
		ClipboardObserver.getInstance();
	}

	/**
	 * Wake up the sniffing process and return instance.
	 * @return
	 */
	public static ClipboardObserver getInstance() {
		if (! INSTANCE.goon)
			INSTANCE.goon = true;
		if (!INSTANCE.thread.isAlive())
			INSTANCE.thread.start();
		
		return INSTANCE;
	}
}
